package middleware

import (
	ijwt "JK-Junior-Go-Engineer-Camp/webook/internal/web/jwt"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
	"net/http"
)

type LoginJWTMiddlewareBuilder struct {
	ijwt.Handler
}

func NewLoginJWTMiddlewareBuilder(hdl ijwt.Handler) *LoginJWTMiddlewareBuilder {
	return &LoginJWTMiddlewareBuilder{Handler: hdl}
}

// CheckLogin 使用了JWT进行登录校验
func (m *LoginJWTMiddlewareBuilder) CheckLogin() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		// 忽略掉 登录和注册接口
		path := ctx.Request.URL.Path
		if path == "/users/signup" ||
			path == "/users/login" ||
			path == "/users/login_sms/code/send" ||
			path == "/users/login_sms" ||
			path == "/oauth2/wechat/authurl" ||
			path == "/oauth2/wechat/callback" {
			// 不需要登录校验
			return
		}
		tokenStr := m.ExtractToken(ctx)
		var userClaims ijwt.UserClaims
		// 这个token是jwt包下的结构体
		token, err := jwt.ParseWithClaims(tokenStr, &userClaims, func(token *jwt.Token) (interface{}, error) {
			return ijwt.JWTKey, nil
		})
		if err != nil { // token是伪造的
			ctx.AbortWithStatus(http.StatusUnauthorized)
			return
		}
		// 两种写法都可以，不过一般判断一下Valid就可以了
		// if token==nil||!token.Valid||userClaims.ExpiresAt.Before(time.Now()){}
		if !token.Valid { // token可能是非法或者过期了
			ctx.AbortWithStatus(http.StatusUnauthorized)
			return
		}
		// 比较User-Agent，增强登录安全性
		if userClaims.UserAgent != ctx.GetHeader("User-Agent") {
			// 你现在可以返回一个401回去，
			// 但是后期我们讲到监控告警的时候，这个地方要埋点，意思就是你需要在这里记录一下
			// 正常用户是不会进来这里的，大概率是攻击者
			ctx.AbortWithStatus(http.StatusUnauthorized)
			return
		}

		// 检查ssid是否有效
		err = m.CheckSession(ctx, userClaims.Ssid)
		if err != nil {
			ctx.AbortWithStatus(http.StatusUnauthorized)
			return
		}
		// 为了方便后面别的地方需要userClaims
		// 这样的话，别的地方用就不用重新解析了
		ctx.Set("user", userClaims)
	}
}
